#include "TLE92108_Driver.h"

#pragma region //===========字段==========
static sSPI_DRIVER *pGateDrv;	//多MOSFET驱动对象
TLE92108_Reg_t reg[3];
GPIO_TypeDef *CS_Port[] =
{ 
	GATE_CS1_GPIO_Port, GATE_CS2_GPIO_Port, GATE_CS3_GPIO_Port
};
uint16_t CS_Pin[] =
{
	GATE_CS1_Pin, GATE_CS2_Pin, GATE_CS3_Pin
};
#pragma endregion

#pragma region //===========私有函数=============
/**
*@brief	  微秒延时函数
*@param		time_ms:要延时微秒时间数
*@return	无
*/
void delay_us( uint32_t time_us )
{
	for (int i = 0; i < 84; i++);
//	uint32_t fac_us = SysTick->LOAD / 1000;
//	uint32_t	temp = SysTick->VAL + time_us * fac_us;
//	if (temp > SysTick->LOAD) temp -= SysTick->LOAD;
//	if (temp > SysTick->VAL)
//		while(temp > SysTick->VAL);							/*等待时间到达*/
//	else
//		while(temp < SysTick->VAL);							/*等待时间到达*/
}
uint8_t ReadTLE92108Reg(uint16_t *dst_reg, uint16_t *src_reg, uint8_t i)
{
	TLE92108_Protocol_t buf;
	HAL_GPIO_WritePin(CS_Port[i], CS_Pin[i], GPIO_PIN_RESET); //CS=0
	delay_us(1);
	buf.RegAddr = GetRegAddr(src_reg, 0);
	SPI_Tx_Rx(pGateDrv, buf.Byte, buf.Byte, 3);
	*dst_reg = __REV16(buf.ReadData);
	delay_us(1);
	HAL_GPIO_WritePin(CS_Port[i], CS_Pin[i], GPIO_PIN_SET); //CS=1
	delay_us(1);
	return buf.Byte[0];
}
uint8_t RdWrTLE92108Reg(uint16_t *dst_reg, uint16_t data, uint8_t i)
{
	TLE92108_Protocol_t buf;
	HAL_GPIO_WritePin(CS_Port[i], CS_Pin[i], GPIO_PIN_RESET); //CS=0
	delay_us(1);
	buf.RegAddr = GetRegAddr(dst_reg, 1);
	buf.Word = __REV16(data);
	SPI_Tx_Rx(pGateDrv, buf.Byte, buf.Byte, 3);
	delay_us(1);
	HAL_GPIO_WritePin(CS_Port[i], CS_Pin[i], GPIO_PIN_SET); //CS=1
	delay_us(1);
	return buf.Byte[0];
}
void ClearStatus(uint8_t cs)
{
	TLE92108_Protocol_t tx_buf, rx_buf;
	HAL_GPIO_WritePin(CS_Port[cs], CS_Pin[cs], GPIO_PIN_RESET); //CS=0
	delay_us(1);
	tx_buf.RegAddr = GetRegAddr(&TLE92108_Reg->GENSTAT, 1);
	SPI_Tx_Rx(pGateDrv, rx_buf.Byte, tx_buf.Byte, 3);
	reg[cs].GENSTAT = __REV16(rx_buf.ReadData);
	delay_us(1);
	HAL_GPIO_WritePin(CS_Port[cs], CS_Pin[cs], GPIO_PIN_SET); //CS=1
	delay_us(1);
}
void ClearFS(uint8_t cs)
{
	ReadTLE92108Reg(&reg[cs].GENCTRL1, &TLE92108_Reg->GENCTRL1, cs);
	ReadTLE92108Reg(&reg[cs].GENCTRL2, &TLE92108_Reg->GENCTRL2, cs);
	
	ClearStatus(cs);
	
	reg[cs].GENCTRL1 |= WDTRIG; //对该寄存器的任何写访问都必须反转WDTRIG位。否则，设备进入故障安全模式。参见5.2.3章。
	RdWrTLE92108Reg(&TLE92108_Reg->GENCTRL1, reg[cs].GENCTRL1, cs);
	reg[cs].GENCTRL1 &= ~WDTRIG;
	RdWrTLE92108Reg(&TLE92108_Reg->GENCTRL1, reg[cs].GENCTRL1, cs);
}
#pragma endregion

#pragma region //===========方法===============
/*
********************************************************************************
 *描述: 初始化TLE92108
 ******************************************************************************/
int TLE92108_Init(void *handle/*[I]指向外设句柄*/,
	osSemaphoreId DoneSemId/*[I]SPI通讯完成信号量句柄*/)
{
	HAL_GPIO_WritePin(GATE_CS1_GPIO_Port, GATE_CS1_Pin, GPIO_PIN_SET); //CS=1
	HAL_GPIO_WritePin(GATE_CS2_GPIO_Port, GATE_CS2_Pin, GPIO_PIN_SET); //CS=1
	HAL_GPIO_WritePin(GATE_CS3_GPIO_Port, GATE_CS3_Pin, GPIO_PIN_SET); //CS=1
	
	if (SPI_Init(&pGateDrv, (SPI_HandleTypeDef*)handle, DoneSemId) < 0)
		return -1;
	
	//复位所有TLE92108器件
	HAL_GPIO_WritePin(EN_GATE_GPIO_Port, EN_GATE_Pin, GPIO_PIN_RESET); //EN=0
	osDelay(2);
	HAL_GPIO_WritePin(EN_GATE_GPIO_Port, EN_GATE_Pin, GPIO_PIN_SET); //EN=1
	osDelay(2);
	
	//测试SPI是否正常
	for (size_t i = 0; i < 3; i++)
	{
		ReadTLE92108Reg(&reg[i].DEVID, &TLE92108_Reg->DEVID, i);
		if (reg[i].DEVID != 1)
		{
			return -2;
		}
		//读状态寄存器
		ReadTLE92108Reg(&reg[i].GENSTAT, &TLE92108_Reg->GENSTAT, i);
		ReadTLE92108Reg(&reg[i].DSOV, &TLE92108_Reg->DSOV, i);
		ReadTLE92108Reg(&reg[i].HBVOUT_PWMERR, &TLE92108_Reg->HBVOUT_PWMERR, i);
		ReadTLE92108Reg(&reg[i].EFF_TDON_OFF[0], &TLE92108_Reg->EFF_TDON_OFF[0], i);
		ReadTLE92108Reg(&reg[i].EFF_TDON_OFF[1], &TLE92108_Reg->EFF_TDON_OFF[1], i);
		ReadTLE92108Reg(&reg[i].EFF_TDON_OFF[2], &TLE92108_Reg->EFF_TDON_OFF[2], i);
		ReadTLE92108Reg(&reg[i].TRISE_FALL[0], &TLE92108_Reg->TRISE_FALL[0], i);
		ReadTLE92108Reg(&reg[i].TRISE_FALL[1], &TLE92108_Reg->TRISE_FALL[1], i);
		ReadTLE92108Reg(&reg[i].TRISE_FALL[2], &TLE92108_Reg->TRISE_FALL[2], i);
		
		//关闭看门狗--调试用
//		ReadTLE92108Reg(&reg[i].GENCTRL1, &TLE92108_Reg->GENCTRL1, i);
//		ReadTLE92108Reg(&reg[i].GENCTRL2, &TLE92108_Reg->GENCTRL2, i);
//		reg[i].GENCTRL1 ^= WDTRIG;//对该寄存器的任何写访问都必须反转WDTRIG位。否则，设备进入故障安全模式。参见5.2.3章。
//		reg[i].GENCTRL1 |= UNLOCK;
//		RdWrTLE92108Reg(&TLE92108_Reg->GENCTRL1, &reg[i].GENCTRL1, i);
//		reg[i].GENCTRL2 |= WDDIS;
//		RdWrTLE92108Reg(&TLE92108_Reg->GENCTRL2, &reg[i].GENCTRL2, i);
	}
	
	//读TLE92108寄存器内容
	uint8_t ret = 0;
	for (size_t i = 0; i < 3; i++)
	{
		reg[i].GENCTRL1 = VSOVTH | UNLOCK | FMODE | OCEN | WDPER | WDTRIG; //2个电流感测是单向的,放大倍数是10,过电流关断使能;Vs过电压阈值29V;看门狗溢出周期200ms;
		ret = RdWrTLE92108Reg(&TLE92108_Reg->GENCTRL1, reg[i].GENCTRL1, i);
		reg[i].GENCTRL2 = BD_PASS | WDDIS | MSKTDREG; //在PWM期间后充电阶段启用;桥驱动处于被动模式;看门狗开启
		ret |= RdWrTLE92108Reg(&TLE92108_Reg->GENCTRL2, reg[i].GENCTRL2, i);
		if (ret > 0x40) 
		{
			ClearFS(i);
		}
		ClearStatus(i);
		ret = ReadTLE92108Reg(&reg[i].GENCTRL1, &TLE92108_Reg->GENCTRL1, i);
		ret |= ReadTLE92108Reg(&reg[i].GENCTRL2, &TLE92108_Reg->GENCTRL2, i);
//		reg[i].GENCTRL2 = 0x4180; //在PWM期间后充电阶段启用;桥驱动处于被动模式;看门狗开启
		ret |= ReadTLE92108Reg(&reg[i].HBMODE, &TLE92108_Reg->HBMODE, i);
		ret |= ReadTLE92108Reg(&reg[i].PWMSET, &TLE92108_Reg->PWMSET, i);
	}
	return ret;
}
/*
********************************************************************************
 *描述: 配置电流传感器: cs=芯片序号, no=传感器编号[0, 1], side=电流感测位置, k=放大器增益, dir=电流是单向还是双向的
 ******************************************************************************/
void TLE_ConfigCurrentSensor(uint8_t cs, uint8_t no, CSA_Level side, CSA_Gain k, CSA_Direction dir, CapacitorCCSO cap)
{
	TLE92108_Protocol_t buf;
	//使能CSAi,配置电流检测放大器电平
	buf.RegAddr = GetRA(HBIDIAG, 1);
	reg[cs].HBIDIAG &= ~((CSA1_OFF | CSA1L) << no);
	reg[cs].HBIDIAG |= (side << no);
	buf.Word = __REV16(reg[cs].HBIDIAG);
	HAL_GPIO_WritePin(CS_Port[cs], CS_Pin[cs], GPIO_PIN_RESET); //CS=0
	SPI_Tx_Rx(pGateDrv, buf.Byte, buf.Byte, 3);
	HAL_GPIO_WritePin(CS_Port[cs], CS_Pin[cs], GPIO_PIN_SET); //CS=1
	//配置放大器增益和极性
	buf.RegAddr = GetRA(GENCTRL1, 1);
	reg[cs].GENCTRL1 ^= WDTRIG; //对该寄存器的任何写访问都必须反转WDTRIG位
	no *= sCS;
	reg[cs].GENCTRL1 &= ~((CSAG1 | CSD1) << no);
	reg[cs].GENCTRL1 |= (k | dir) << no;
	buf.Word = __REV16(reg[cs].GENCTRL1);
	HAL_GPIO_WritePin(CS_Port[cs], CS_Pin[cs], GPIO_PIN_RESET); //CS=0
	SPI_Tx_Rx(pGateDrv, buf.Byte, buf.Byte, 3);
	HAL_GPIO_WritePin(CS_Port[cs], CS_Pin[cs], GPIO_PIN_SET); //CS=1
	
	buf.RegAddr = GetRA(PWM_IDCHG_ACT, 1);
	reg[cs].PWM_IDCHG_ACT &= ~CCSO;
	reg[cs].PWM_IDCHG_ACT |= cap;
	buf.Word = __REV16(reg[cs].PWM_IDCHG_ACT);
	HAL_GPIO_WritePin(CS_Port[cs], CS_Pin[cs], GPIO_PIN_RESET); //CS=0
	SPI_Tx_Rx(pGateDrv, buf.Byte, buf.Byte, 3);
	HAL_GPIO_WritePin(CS_Port[cs], CS_Pin[cs], GPIO_PIN_SET); //CS=1
}
/*
********************************************************************************
 *描述: 配置过电流参数: cs=芯片序号, no=电流传感器编号[0, 1], th=过流检测门限(分单向双向), ft=CSOx过流滤波时间
 ******************************************************************************/
void TLE_ConfigOverCurrent(uint8_t cs, uint8_t no, VcsoOC_Threshold th, OC_FilterTime ft)
{
	TLE92108_Protocol_t buf;
	
	//配置过流门限
	buf.RegAddr = GetRA(GENCTRL2, 1);
	uint8_t i = no * sOCTH;
	reg[cs].GENCTRL2 &= ~(OCTH1 << i);
	reg[cs].GENCTRL2 |= (th << i);
	buf.Word = __REV16(reg[cs].GENCTRL2);
	HAL_GPIO_WritePin(CS_Port[cs], CS_Pin[cs], GPIO_PIN_RESET); //CS=0
	SPI_Tx_Rx(pGateDrv, buf.Byte, buf.Byte, 3);
	HAL_GPIO_WritePin(CS_Port[cs], CS_Pin[cs], GPIO_PIN_SET); //CS=1
	
	//配置过流滤波时间
	buf.RegAddr = GetRA(HBIDIAG, 1);
	i = no * sOCFILT;
	reg[cs].HBIDIAG &= ~(OC1FILT << i);
	reg[cs].HBIDIAG |= (ft << i);
	buf.Word = __REV16(reg[cs].HBIDIAG);
	HAL_GPIO_WritePin(CS_Port[cs], CS_Pin[cs], GPIO_PIN_RESET); //CS=0
	SPI_Tx_Rx(pGateDrv, buf.Byte, buf.Byte, 3);
	HAL_GPIO_WritePin(CS_Port[cs], CS_Pin[cs], GPIO_PIN_SET); //CS=1
	
	//使能过电流关断
	buf.RegAddr = GetRA(GENCTRL1, 1);
	reg[cs].GENCTRL1 |= OCEN;
	reg[cs].GENCTRL1 ^= WDTRIG;
	buf.Word = __REV16(reg[cs].GENCTRL1);
	HAL_GPIO_WritePin(CS_Port[cs], CS_Pin[cs], GPIO_PIN_RESET); //CS=0
	SPI_Tx_Rx(pGateDrv, buf.Byte, buf.Byte, 3);
	HAL_GPIO_WritePin(CS_Port[cs], CS_Pin[cs], GPIO_PIN_SET); //CS=1
}
/*
********************************************************************************
 *描述: 把所有桥驱动进入高阻模式并关闭看门狗
 ******************************************************************************/
void TLE_GotoStandbyMode(void)
{
	for (size_t i = 0; i < 3; i++)
	{
		//关闭看门狗, 桥驱动处于被动模式
		reg[i].GENCTRL1 |= UNLOCK; // 解锁
		reg[i].GENCTRL1 ^= WDTRIG;
		RdWrTLE92108Reg(&TLE92108_Reg->GENCTRL1, reg[i].GENCTRL1, i);
		reg[i].GENCTRL2 |= BD_PASS | WDDIS; // 桥驱动处于被动模式; 关闭看门狗
		RdWrTLE92108Reg(&TLE92108_Reg->GENCTRL2, reg[i].GENCTRL2, i);	
		//将有关通道设置为高阻抗(OFF):设置HBxMODE为0
		reg[i].HBMODE = 0; //清原数据=>即等于HB_HI(LSx,HSx保持OFF)
		RdWrTLE92108Reg(&TLE92108_Reg->HBMODE, reg[i].HBMODE, i);
	}
}
/*
********************************************************************************
 *描述: 将指定H桥组进入高阻模式
 ******************************************************************************/
void TLE_GotoHighImpedanceMode(uint8_t cs/*芯片序号0,1,2*/, uint8_t group/*[I]组:0=1,2;1=3,4;2=5,6;3=7,8;*/)
{
	//1#将有关通道设置为高阻抗(OFF):设置HBxMODE为0
	uint8_t md_bit = group * 4;
	reg[cs].HBMODE &= ~(0x000F << md_bit); //清group和group+1字段原数据=>即等于HB_HI(LSx,HSx保持OFF),其它不受影响
	RdWrTLE92108Reg(&TLE92108_Reg->HBMODE, reg[cs].HBMODE, cs);
}
//TLE92108只支持单极模式:电机电枢驱动电压极性是单一的。需要对同一侧桥臂的两个MOS管进行互补PWM控制。
//优点：启动快，能加速，刹车，能耗制动，能量反馈，调速性能不如双极模式好，但是相差不多，电机特性也比较好。在负载超速时也能提供反向力矩。
//缺点：刹车时，不能减速到0，速度接近0时没有制动力。不能突然倒转。动态性能不好，调速静差稍大。
/*
********************************************************************************
 *描述: 把H桥配置成单极模式.cs=芯片序号, 
 ******************************************************************************/
void TLE_ConfigUnipolarMode(uint8_t cs,
	uint8_t group,//[I]组:0=1,2;1=3,4;2=5,6;3=7,8;
	uint8_t pwni,	//[I]PWM编号:0=PWM1;1=PWM2;2=PWM3;
	uint8_t dir)	//[I]方向:0=正向组,1=反向组;
{
	
	//1#将有关通道设置为高阻抗(OFF):设置HBxMODE为0
	uint8_t md_bit = group * 4;
	reg[cs].HBMODE &= ~(0x000F << md_bit); //清group和group+1字段原数据=>即等于HB_HI(LSx,HSx保持OFF),其它不受影响
	RdWrTLE92108Reg(&TLE92108_Reg->HBMODE, reg[cs].HBMODE, cs);
	if ((reg[cs].GENCTRL2 & BD_PASS) != 0)//桥驱动处于被动模式
	{
		reg[cs].GENCTRL2 &= ~BD_PASS;	//激活模式
		RdWrTLE92108Reg(&TLE92108_Reg->GENCTRL2, reg[cs].GENCTRL2, cs);
		
		ReadTLE92108Reg(&reg[cs].GENCTRL2, &TLE92108_Reg->GENCTRL2, cs);
	}
	
	//2#使能PWM通道,并将其配置到8个半桥HB之一.将PWMiEN设置为1，并将PWMiHB[2:0]设置为group或group+1(dir==1)
	group *= 2;	//每组2个半桥HB组成一个H桥驱动
	pwni *= 4;	//PWMiEN在PWMSET中的位置:每4位控制HB半桥通道使能PWM
	uint8_t hb_bit = pwni + 1; //PWMiHB在PWMSET中的位置
	if (dir != 0) group++;	//反转配置到反向组:HB1为正向组,HB2为反向组
	reg[cs].PWMSET &= ~(7UL << hb_bit); //清PWMiHB[2:0]3位
	reg[cs].PWMSET |= (1 << pwni) | (group << hb_bit); //将PWMiEN设置为1, 将PWMiHB[2:0]设置为group或group+1(dir==1)
	RdWrTLE92108Reg(&TLE92108_Reg->PWMSET, reg[cs].PWMSET, cs);
	
	ReadTLE92108Reg(&reg[cs].PWMSET, &TLE92108_Reg->PWMSET, cs);
	
	//3#使能配置输出.设置HBxMODE为HS_ON,PWMi应用于HBx的高侧, HByMODE为LS_ON低侧常开通
	uint16_t hb_md;
	if (dir == 0) 
	{
		hb_md = HS_ON | (LS_ON << 2); //group:HS is ON; group+1:LS is ON;
	}
	else
	{
		hb_md = LS_ON | (HS_ON << 2); //group+1:HS is ON; group:LS is ON;
	}
	reg[cs].HBMODE |= (hb_md << md_bit); //bit指向低侧位. group指向高侧位
	RdWrTLE92108Reg(&TLE92108_Reg->HBMODE, reg[cs].HBMODE, cs);
	
	ReadTLE92108Reg(&reg[cs].HBMODE, &TLE92108_Reg->HBMODE, cs);
	
	//复位看门狗
	TLE_FeedDog(cs);
}
/*
********************************************************************************
 *描述: 配置过电流参数: no=电流传感器编号[0, 1], th=过流检测门限(分单向双向), ft=CSOx过流滤波时间
 ******************************************************************************/
void TLE_ConfigOverVoltage()
{
}
/*
********************************************************************************
 *描述: 喂狗. 在50或200ms内(根据设置看门狗溢出周期不同)至少喂狗一次
 ******************************************************************************/
void TLE_FeedDog(uint8_t cs)
{
	TLE92108_Protocol_t buf;
	buf.RegAddr = GetRA(GENCTRL1, 1);
	reg[cs].GENCTRL1 ^= WDTRIG;
	buf.Word = __REV16(reg[cs].GENCTRL1);
	HAL_GPIO_WritePin(CS_Port[cs], CS_Pin[cs], GPIO_PIN_RESET); //CS=0
	SPI_Tx_Rx(pGateDrv, buf.Byte, buf.Byte, 3);
	HAL_GPIO_WritePin(CS_Port[cs], CS_Pin[cs], GPIO_PIN_SET); //CS=1
}
#pragma endregion
